热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

几何体|可能会_✿3TheBasics使用QtWidgets进行GUI设计

篇首语:本文由编程笔记#小编为大家整理,主要介绍了✿3-TheBasics-使用QtWidgets进行GUI设计相关的知识,希望对你有一定的参考价值。目录

篇首语:本文由编程笔记#小编为大家整理,主要介绍了✿3-The Basics-使用Qt Widgets进行GUI设计相关的知识,希望对你有一定的参考价值。



目录


      • 介绍Qt widgets
      • 使用Qt Designer创建UI
      • 管理布局
      • 创建自定义部件
      • 创建Qt样式表和自定义主题
        • 使用QSS文件
        • 探索自定义样式
          • 创建自定义样式
          • 使用自定义样式

        • 使用小部件、窗口和对话框

      • 总结




Qt Widgets是一个模块,它提供了一组用于构建经典UI的用户界面(UI)元素。在本章中,你将了解
Qt Widgets模块,并了解基本小部件。我们将了解什么是小部件,以及可用于创建图形用户界面(GUI)的各种小部件。除此之外,还将向你介绍
Qt Designer的布局,并学习如何创建自己的自定义控件。我们将仔细研究Qt在轻松设计外观光滑的GUI时能为我们提供什么。在本章的开头,你将了解Qt提供的小部件类型及其功能。之后,我们将完成一系列步骤,并使用Qt设计我们的第一个表单应用程序。然后,你将学习样式表、Qt样式表(
Qt Style Sheets)(QSS文件)和主题化。

本章将介绍以下主要主题:


  • 介绍Qt小部件
  • 使用Qt Designer创建UI
  • 管理布局
  • 创建自定义小部件
  • 创建Qt样式表和自定义主题
  • 探索自定义样式
  • 使用小部件、窗口和对话框

本章结束时,你将了解GUI元素及其相应的C++类的基础知识,如何在不编写一行代码的情况下创建自己的UI,以及如何使用样式表自定义UI的外观。


介绍Qt widgets

widget(小部件)是GUI的基本元素,它也被称为UI控件。它从底层平台接受不同的用户事件,例如鼠标和键盘事件(以及其他事件)。我们使用不同的小部件创建UI。曾经有一段时间,所有GUI控件都是从头开始编写的。Qt小部件通过开发带有现成GUI控件的桌面GUI来减少时间,Qt广泛使用继承的概念。所有小部件都继承自QObjectQWidget是一个基本的小部件,是所有UI小部件的基类;它包含描述小部件所需的大多数属性,以及几何体、颜色、鼠标、键盘行为、工具提示等属性。让我们看看下图中的QWidget继承层次结构:


  • QPushButton 用于命令应用程序执行特定操作。
  • QCheckBox 允许用户进行二进制选择。
  • QRadioButton 允许用户从一组相互排斥的选项中仅做出一个选择。
  • QFrame 显示一个框架。
  • QLabel 用于显示文本或图像。
  • QLineEdit 允许用户输入和编辑单行纯文本。
  • QTabWidget 用于在选项卡式窗口小部件的堆栈中显示与每个选项卡相关的页面。

使用Qt小部件的优点之一是它的继承系统。从QObject继承的任何对象都具有父子关系。这种关系为开发人员提供了许多便利,例如:


  • 当一个小部件被销毁时,由于父子层次结构,它的所有子部件也已经被销毁了。这样可以避免内存泄漏。
  • 通过使用findChild()findChildren()可以找到给定QWidget类的子类。
  • Qwidget中的子部件会自动出现在父部件中。

典型的C++程序在主main()函数返回时终止,但在GUI应用程序中,我们不能这样做,或者应用程序将无法使用。因此,我们需要GUI一直存在,直到用户关闭窗口。为了实现这一点,程序应该在循环中运行,直到发生这种情况。GUI应用程序等待用户输入事件。

让我们使用简单的GUI程序,使用QLabel显示一段文本:

#include
#include
int main(int argc, char *argv[])
QApplication app(argc, argv);
QLabel myLabel;
myLabel.setText("Hello World!");
myLabel.show();
return app.exec();

记住在.pro文件中添加以下行,用于启用Qt Widgets模块:

QT += widgets


使用Qt Designer创建UI


Qt Widgets模块附带了现成的小部件。Qt提供了一个通过拖放方法创建UI的选项。让我们通过简单地将这些小部件从小部件框区域拖动到表单编辑器区域来探索它们。在项目到达表单编辑器区域之前,不要释放鼠标或触控板。下面的屏幕截图显示了小部件框部分中可用的不同类型的小部件。我们在表单编辑器区域中添加了一些现成的小部件,如标签、按钮、单选按钮、复选框、组合框、进度条和行编辑。这些小部件是非常常用的小部件。你可以在 [属性编辑器] 中浏览特定于小部件的属性。

你可以预览UI:Tools->Form Editor->Preview

还可以查看UI对应的C++代码:Tools->C+±>Inspect C++ Code Model…


管理布局

Qt提供了一组方便的布局管理类,可以在另一个小部件中自动排列子小部件,以确保UI保持可用。QLayout类是所有布局管理器的基类。还可以通过重新实现setGeometry()、sizeHint()、addItem()、itemAt()、takeAt()和minimumSize()函数来创建自己的布局管理器。请注意,一旦删除布局管理器,布局管理也将停止。以下列表简要介绍了主要布局类:


  • QVBoxLayout 垂直排列小部件。
  • QHBoxLayout 水平排列小部件。
  • QGridLayout 在网格中布局小部件。
  • QFormLayout 管理各种形式的输入小部件及其相关标签。
  • QStackedLayout 提供了一组小部件,一次只能看到一个小部件。

QLayout通过从QObject和QLayoutItem继承来使用多个继承。QLayout的子类是QBoxLayout、QGridLayout、QFormLayout和QStackedLayout。QVBoxLayout和QHBoxLayout继承自QBoxLayout,并添加了方向信息。让我们使用Qt Designer模块来布置几个QPushButtons。

QVBoxLayout:

对应的完整C++代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
class Ui_MainWindow
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout;
QPushButton *pushButton;
QPushButton *pushButton_2;
QPushButton *pushButton_3;
QPushButton *pushButton_4;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QStringLiteral("MainWindow"));
MainWindow->resize(378, 282);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
verticalLayout = new QVBoxLayout(centralWidget);
verticalLayout->setSpacing(6);
verticalLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
pushButton = new QPushButton(centralWidget);
pushButton->setObjectName(QStringLiteral("pushButton"));
verticalLayout->addWidget(pushButton);
pushButton_2 = new QPushButton(centralWidget);
pushButton_2->setObjectName(QStringLiteral("pushButton_2"));
pushButton_2->setMinimumSize(QSize(366, 15));
verticalLayout->addWidget(pushButton_2);
pushButton_3 = new QPushButton(centralWidget);
pushButton_3->setObjectName(QStringLiteral("pushButton_3"));
verticalLayout->addWidget(pushButton_3);
pushButton_4 = new QPushButton(centralWidget);
pushButton_4->setObjectName(QStringLiteral("pushButton_4"));
verticalLayout->addWidget(pushButton_4);
MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QStringLiteral("menuBar"));
menuBar->setGeometry(QRect(0, 0, 378, 17));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QStringLiteral("statusBar"));
MainWindow->setStatusBar(statusBar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
// setupUi
void retranslateUi(QMainWindow *MainWindow)
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", Q_NULLPTR));
pushButton->setText(QApplication::translate("MainWindow", "PushButton1", Q_NULLPTR));
pushButton_2->setText(QApplication::translate("MainWindow", "PushButton2", Q_NULLPTR));
pushButton_3->setText(QApplication::translate("MainWindow", "PushButton3", Q_NULLPTR));
pushButton_4->setText(QApplication::translate("MainWindow", "PushButton4", Q_NULLPTR));
// retranslateUi
;
namespace Ui
class MainWindow: public Ui_MainWindow ;
// namespace Ui
QT_END_NAMESPACE

这个程序演示了如何使用垂直布局对象。请注意,QWidget实例widget将成为应用程序的主窗口。在这里,布局被直接设置为顶层布局。添加到addWidget()方法的第一个按钮占据版面的顶部,而最后一个按钮占据版面的底部。
如果没有在QWidget构造函数中设置父窗口,那么以后必须使用QWidget::setLayout()安装布局并重新分配到小部件实例。

QGridLayout:
你还可以通过C++代码动态添加网格布局,如下面的代码片段所示:

QWidget *widget = new QWidget;
QPushButton *pushBtn1 = new QPushButton( "Push Button 1");
QPushButton *pushBtn2 = new QPushButton( "Push Button 2");
QPushButton *pushBtn3 = new QPushButton( "Push Button 3");
QPushButton *pushBtn4 = new QPushButton( "Push Button 4");
QGridLayout *gridLayout = new QGridLayout(widget);
gridLayout->addWidget(pushBtn1);
gridLayout->addWidget(pushBtn2);
gridLayout->addWidget(pushBtn3);
gridLayout->addWidget(pushBtn4);
widget->show();

创建自定义部件

自定义小部件可以是一个或多个放置在一起的Qt小部件的组合,也可以从头开始编写。我们将从QLabel创建一个简单的标签小部件,作为我们的第一个自定义小部件。一个自定义小部件集合可以有多个自定义小部件。
New->Other Project->Qt Custom Designer Widget,步骤如下:



工程目录:

展开Project Explorer视图并打开mylabel.h文件。我们将修改内容以扩展功能。在自定义小部件类名之前添加QDESIGNER_WIDGET_EXPORT宏,以确保在动态链接库(dynamic-link library:DLL)或共享库中正确导出该类。你的自定义小部件可能在没有此宏的情况下工作,但添加此宏是一个很好的做法。插入宏后,必须将#include添加到头文件中。mylabel.h修改如下:

#ifndef MYLABEL_H
#define MYLABEL_H
#include
#include
class QDESIGNER_WIDGET_EXPORT MyLabel: public QLabel
Q_OBJECT
Q_PROPERTY(bool multiLine READ isMultiLine WRITE setMultiLine)
Q_PROPERTY(Qt::GlobalColor color READ getColor WRITE setColor)
private:
bool m_isMultiLine = false;
Qt::GlobalColor m_color = Qt::GlobalColor::black;
public:
MyLabel(QWidget *parent = 0);
void setMultiLine(bool isMultiLine);
bool isMultiLine() const return m_isMultiLine;
void setColor(Qt::GlobalColor color);
Qt::GlobalColor getColor() return m_color;
;
#endif

mylabel.cpp代码如下:

#include "mylabel.h"
MyLabel::MyLabel(QWidget *parent): QLabel(parent)
void MyLabel::setMultiLine(bool isMultiLine) m_isMultiLine = isMultiLine;
void MyLabel::setColor(Qt::GlobalColor color) m_color = color;


注:
在某些平台上,构建系统可能会删除Qt Designer模块创建新小部件所需的符号,使其无法使用。使用QDESIGNER_WIDGET_EXPORT宏可确保符号保留在这些平台上。这在创建跨平台库时非常重要。在其他平台上没有副作用。


mylabelplugin.h

#ifndef MYLABELPLUGIN_H
#define MYLABELPLUGIN_H
#include
class MyLabelPlugin : public QObject, public QDesignerCustomWidgetInterface
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
MyLabelPlugin(QObject *parent = 0);

bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget *createWidget(QWidget *parent);
void initialize(QDesignerFormEditorInterface *core);
private:
bool m_initialized;
;
#endif

可以看到MyLabelPlugin类继承自类QDesignerCustomWidgetInterface,这个类允许Qt Designer去访问和创建自定义小部件。
请注意,你得更改头文件如下,以避免depressed warnings,如下:

修改为如下,则不报depressed warnings:

#include

mylabelplugin.cpp

#include "mylabel.h"
#include "mylabelplugin.h"
#include
MyLabelPlugin::MyLabelPlugin(QObject *parent): QObject(parent)
m_initialized = false;

void MyLabelPlugin::initialize(QDesignerFormEditorInterface * /* core */)
if (m_initialized)
return;
// Add extension registrations, etc. here
m_initialized = true;

bool MyLabelPlugin::isInitialized() const return m_initialized;
QWidget *MyLabelPlugin::createWidget(QWidget *parent) return new MyLabel(parent);
QString MyLabelPlugin::name() const return QLatin1String("MyLabel");
QString MyLabelPlugin::group() const return QLatin1String("");
QIcon MyLabelPlugin::icon() const return QIcon();
QString MyLabelPlugin::toolTip() const return QLatin1String("");
QString MyLabelPlugin::whatsThis() const return QLatin1String("");
bool MyLabelPlugin::isContainer() const return false;
QString MyLabelPlugin::domXml() const
return QLatin1String("\\n\\n");

QString MyLabelPlugin::includeFile() const return QLatin1String("mylabel.h");
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(mylabelplugin, MyLabelPlugin)
#endif

请不要删除生成的函数。你可以给name()、group()、icon()指定值。注意&#xff0c;如果你不给icon()指定值&#xff0c;Qt Designer会使用默认的Qt icon。

你可以看到&#xff0c;isContainer()返回false在MyLabel&#xff0c;MyFrame返回true。因为MyLabel不是设计用来作为其他小部件的容器的&#xff0c;而MyFrame在创建时就勾选了“The widget is a container”。
Qt Designer调用createWidget()去生成一个MyLabelMyFrame的实例。

我们指定myframeplugin.cpp中的group()值&#xff0c;如下&#xff1a;

QString MyFramePlugin::group() const return QLatin1String("My Container");

要创建具有自定义几何体或任何其他属性的小部件&#xff0c;则在domXML()方法中指定这些属性。该函数返回可扩展标记语言&#xff08;XML&#xff09;片段&#xff0c;小部件工厂(the widget factory)使用该片段创建具有定义属性的自定义小部件。
让我们指定MyLable宽&#61;100px&#xff0c;高&#61;16px&#xff0c;如下&#xff1a;

QString MyLabelPlugin::domXml() const
return "\\n"
"\\n"
"\\n"
"<rect>\\n"
"<x>0x>\\n"
"<y>0y>\\n"
"<width>100width>\\n"
"<height>16height>\\n"
"rect>\\n"
"property>\\n"
"\\n"
"<string>MyLabelstring>\\n"
"property>\\n"
"widget>\\n"
"ui>\\n";

现在我们看看MyWidgets.pro文件&#xff0c;如下。
它包含qmake所需的所有信息去构建自定义小部件集合库。

#MyWidgets.pro
CONFIG &#43;&#61; plugin debug_and_release
TARGET &#61; $$qtLibraryTarget(mylabelplugin)
TEMPLATE &#61; lib
HEADERS &#61; mylabelplugin.h
SOURCES &#61; mylabelplugin.cpp
RESOURCES &#61; icons.qrc
LIBS &#43;&#61; -L.
greaterThan(QT_MAJOR_VERSION, 4)
QT &#43;&#61; designer
else
CONFIG &#43;&#61; designer

target.path &#61; $$[QT_INSTALL_PLUGINS]/designer
INSTALLS &#43;&#61; target
include(mylabel.pri)

可以看到&#xff0c;这个工程是一个库类型&#xff0c;并且被配置用作一个插件。

现在&#xff0c;让我们运行qmake并在Release模式下构建这个库。

Build后&#xff0c;在项目所在目录生成如下文件夹&#xff1a;

在Windows平台上&#xff0c;可以手动将新生成的文件夹里的release目录下的mywidgetcollectionplugin.dll复制到D:\\Qt\\6.0.0\\mingw81_64\\plugins\\designer路径下。这个路径及文件扩展名依不同操作系统而异。如果不做这样的拷贝操作&#xff0c;就无法在designer.exe窗口看到我们自定义的插件。

此时&#xff0c;我们已经创建了我们自定义的插件。
现在&#xff0c;在D:\\Qt\\6.0.0\\mingw81_64\\bin目录下找到designer.exe&#xff0c;双击打开。
可以看到我们自定义的部件&#xff1a;

单击“创建”按钮&#xff0c;将MyLabel拖到MyFrame里面。

你还可以在属性编辑器中看到创建的MyLabel的属性&#xff1a;自定义QLabel下的multiLine、color属性。

你现在已经成功创建了你的自定义部件&#xff0c;并拥有新的属性。你也可以通过组合不同的部件创建更复杂的部件。



你还可以在以下Qt文档链接中找到带有示例的详细说明&#xff1a;
https://doc.qt.io/qt-6/designer-creating-custom-widgets.html



创建Qt样式表和自定义主题

Qt提供了几种定制UI外观的方法。Qt样式表(Qt Style Sheet)是在不进行复杂编码的情况下改变小部件外观的最简单方法之一。Qt样式表语法与超文本标记语言(html)/级联样式表(CSS)语法相同。样式表由一系列样式规则组成。样式规则由选择器和声明组成。选择器指定将受样式规则影响的小部件&#xff0c;声明指定小部件的属性。样式规则的声明部分是一个属性列表&#xff0c;作为键值对&#xff0c;包含在中&#xff0c;用分号分隔。

让我们来看一个简单的QPushButton样式表语法&#xff1a;

QPushButtoncolor:green; background-color:

推荐阅读
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • C++ STL复习(13)容器适配器
    STL提供了3种容器适配器,分别为stack栈适配器、queue队列适配器以及priority_queue优先权队列适配器。不同场景下,由于不同的序列式 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 我用Tkinter制作了一个图形用户界面,有两个主按钮:“开始”和“停止”。请您就如何使用“停止”按钮终止“开始”按钮为以下代码调用的已运行功能提供建议 ... [详细]
  • 引号快捷键_首选项和设置——自定义快捷键
    3.3自定义快捷键(CustomizingHotkeys)ChemDraw快捷键由一个XML文件定义,我们可以根据自己的需要, ... [详细]
author-avatar
男人--沉默底线
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有